3
3
.
.
3
3
.
.
5
5
C
C
r
r
e
e
a
a
t
t
e
e
V
V
i
i
e
e
w
w
s
s
f
f
r
r
o
o
m
m
A
A
r
r
r
r
a
a
y
y
u
u
s
s
i
i
n
n
g
g
F
F
o
o
r
r
E
E
a
a
c
c
h
h
I
I
n
n
f
f
o
o
[
[
R
R
]
]
[
[
R
R
]
]
[
[
R
R
]
]
This tutorial shows how to use SwiftUI ForEach Loop to create View from fixed size Array.
Output
Content
ForEach(elements) (Use Identifiable and let id = UUID() to automatically generate unique ids)
ForEach(leftArray, id: \.myid) (You can use this if you can provide your own unique id)
ForEach(0..<elements.count (Might crash application if dimension changes)
ForEach(elements.indices) (Use this if you need access to index)
Wrap Array (To avoid index out of bounds)
F
F
o
o
r
r
E
E
a
a
c
c
h
h
(
(
e
e
l
l
e
e
m
m
e
e
n
n
t
t
s
s
)
)
In this example our struct extends from Identifiable and has id property which uses UUID() to get unique values.
This allows us to use ForEach Loop in its simples form as highlighted in Yellow.
ContentView.swift
struct Element : Identifiable {
let id = UUID()
let offset : CGFloat
let name : String
}
struct ContentView: View {
@State var elements : [Element] = [
Element( offset:20, name:"FIRST" ),
Element( offset:40, name:"SECOND"),
Element( offset:60, name:"THIRD" )
]
var body: some View {
ZStack {
ForEach(elements) { element in
Text(element.name).offset(y: element.offset)
}
}
}
}
F
F
o
o
r
r
E
E
a
a
c
c
h
h
(
(
l
l
e
e
f
f
t
t
A
A
r
r
r
r
a
a
y
y
,
,
i
i
d
d
:
:
\
\
.
.
m
m
y
y
i
i
d
d
)
)
In this example our struct has custom id Property which can then be used inside ForEach as shown in Yellow.
ContentView.swift
struct ContentView: View {
struct Element {
let myid : Int
let offset : CGFloat
let name : String
}
@State var elements : [Element] = [
Element( myid:10, offset:20, name:"FIRST" ),
Element( myid:20, offset:40, name:"SECOND"),
Element( myid:30, offset:60, name:"THIRD" )
]
var body: some View {
ZStack {
ForEach(leftArray, id: \.myid) { element in
Text(element.name).offset(y: element.offset)
}
}
}
}
F
F
o
o
r
r
E
E
a
a
c
c
h
h
(
(
0
0
.
.
.
.
<
<
e
e
l
l
e
e
m
m
e
e
n
n
t
t
s
s
.
.
c
c
o
o
u
u
n
n
t
t
)
)
This solution can be used when you need access to the index.
ContentView.swift
struct Element {
let myid : Int
let offset : CGFloat
let name : String
}
struct ContentView: View {
@State var elements : [Element] = [
Element( myid:10, offset:20, name:"FIRST" ),
Element( myid:20, offset:40, name:"SECOND"),
Element( myid:30, offset:60, name:"THIRD" )
]
var body: some View {
ZStack {
ForEach(0..<elements.count) { i in
Text(self.elements[i].name).offset(y: self.elements[i].offset)
}
}
}
}
F
F
o
o
r
r
E
E
a
a
c
c
h
h
(
(
e
e
l
l
e
e
m
m
e
e
n
n
t
t
s
s
.
.
i
i
n
n
d
d
i
i
c
c
e
e
s
s
)
)
This approach is supposed to be safer then ForEach(0..<elements.count) when size of Array might change.
ContentView.swift
struct Element {
let myid : Int
let offset : CGFloat
let name : String
}
struct ContentView: View {
@State var elements : [Element] = [
Element( myid:10, offset:20, name:"FIRST" ),
Element( myid:20, offset:40, name:"SECOND"),
Element( myid:30, offset:60, name:"THIRD" )
]
var body: some View {
ZStack {
ForEach(elements.indices) { i in
Text(self.elements[i].name).offset(y: self.elements[i].offset)
}
}
}
}
W
W
r
r
a
a
p
p
A
A
r
r
r
r
a
a
y
y
ForEach only work on fixed size Arrays.
As soon as you start adding or removing elements you will get: index out of bounds exception.
To avoid this error you can wrap your Array inside a Class as shown below.
ContentView.swift
import SwiftUI
class WrapElements : ObservableObject {
@Published var elements = ["A","B","C"]
}
struct ContentView: View {
@ObservedObject var wrapElements = WrapElements()
var body:some View {
VStack{
ForEach(wrapElements.elements.indices, id: \.self){ index in
Text(self.wrapElements.elements[index])
}
}.onTapGesture{self.wrapElements.elements.removeLast()}
}
}
Without using Class wrapper you will get error as demonstrated with below example.
ContentView.swift
import SwiftUI
struct ContentView: View {
@State var elements = ["A","B","C"]
var body:some View {
VStack{
ForEach(elements.indices, id: \.self){ index in
Text(self.elements[index])
}
}.onTapGesture{self.elements.removeLast()}
}
}
Example 2
import SwiftUI
struct ContentView: View {
@State var elements = ["A","B","C"]
var body:some View {
VStack{
ForEach(elements.indices, id: \.self){ index in
Text(self.elements[index])
}
Button("ADD" ) {self.elements.append("D")}
Button("REMOVE") {self.elements.removeLast()}
}
}
}
Output